<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2023/8/18
 * Time: 11:15
 */

namespace app\logic\cron;


use app\common\lib\DouYinOpenApp;
use app\common\lib\TencentCos;
use app\logic\BaseLogic;
use app\model\bingtian\BingTianNovelModel;
use app\model\douyin\CooperateAppidModel;
use app\model\douyin\PromotionTaskDetailModel;
use app\model\novel\NovelBusinessModel;
use app\model\novel\NovelSpreadModel;
use app\model\reward\RewardPlanModel;
use app\model\user\UserIncomeFlowModel;
use app\model\user\UserModel;
use app\model\user\UserPromotionOrderIncomeModel;
use support\Cache;
use support\Db;

class DouyinLogic extends BaseLogic
{
    protected static $instance;

    protected $insertTaskDatas;

    public function __construct()
    {
        parent::__construct();
    }

    public static function getInstance()
    {
//        if (is_object(self::$instance)) {
//            return self::$instance;
//        }

        return  new self();
    }


    public function getTaskDetailByIds($days=60)
    {
        $startTime = strtotime(date('Y-m-d 00:00:00',strtotime('-'.$days.' day')));
        $endTime = strtotime(date('Y-m-d 23:59:59'));

        //$startTime = strtotime('2023-8-01');
        //$endTime = strtotime('2023-7-31');
        $time = $startTime;

        $appids = CooperateAppidModel::getInstance()->getWhere(['platform' => 1, 'isdel' => 0])->pluck('name', 'appid')->toArray();
        while ($time<=$endTime) {
            $endDateTime = strtotime(date('Y-m-d 23:59:59', $time + (7 * 86400)));
            foreach ($appids as $appid => $name) {
                $result = DouYinOpenApp::getInstance()->searchTaskId($appid, $time, $endDateTime);

                if(!empty($result['data']['task_ids'])){
                    foreach($result['data']['task_ids'] as $taskid){
                        $insert = [
                            'start_time'=>date('Y-m-d 00:00:00',$time),
                            'end_time'=>date('Y-m-d 00:00:00',$endDateTime),
                            'taskid'=>$taskid,
                            'appid'=>$appid,
                        ];
                        $this->autoCreateTableAndInsertData(
                            [
                                'table'=>'video_douyin_promotion_task_id',
                                'keyid'=>'douyin_task_id',
                                'attributes'=>$insert,
                                'update_fields'=>['appid','taskid']
                            ]
                        );

                        $taskDetail = DouYinOpenApp::getInstance()->searchTaskInfo($appid,$taskid,$type=1);
                        if(!empty($taskDetail['data']['tasks'])) {
                            foreach($taskDetail['data']['tasks'] as $task) {
                                $this->autoCreateTableAndInsertData(
                                    [
                                        'table'         => 'video_douyin_promotion_task_detail',
                                        'keyid'         => 'promotion_task_detail_id',
                                        'attributes'    => $task,
                                        'update_fields' => ['appid', 'task_id'],
                                    ]
                                );
                            }
                        }
                    }
                }
            }
            $time = ($endDateTime+1);
        }

        return 'success';
    }

    public function sysncNovelByTaskDetail($isNowTime = false)
    {
        $businessMap = [
            'ttd572a3cf4a4167a901'=>['platform'=>1,'business_id'=>10,'app_name'=>'尖叫故事'],
            'ttf426829b6b141c3f01'=>['platform'=>1,'business_id'=>11,'app_name'=>'奇热故事'],
            'tt7183073eeebc5a1f01'=>['platform'=>1,'business_id'=>12,'app_name'=>'冰糖故事会'],
            'ttbbb6cd0b2489e34c01'=>['platform'=>1,'business_id'=>13,'app_name'=>'冰甜故事会'],
        ];

        //$appids = CooperateAppidModel::getInstance()->getWhere(['platform' => 1, 'isdel' => 0])->pluck('name', 'appid')->toArray();
        foreach ($businessMap as $appid => $business){
            //获取新任务id
            $days = $isNowTime ? 0 : 0;
            $startTime = strtotime(date('Y-m-d 00:00:00',strtotime('-'.$days.' day')));
            $endTime = strtotime(date('Y-m-d 23:59:59'));

            $result = DouYinOpenApp::getInstance()->searchTaskId($appid, $startTime, $endTime);
            $newTaskIds = [];
            if(!empty($result['data']['task_ids'])) {
                $newTaskIds = $result['data']['task_ids'];
            }

            //小说任务id
            $totalTaskIds = NovelSpreadModel::getInstance()->getWhere(['app_id'=>$appid,'isdel'=>0])->pluck('task_id')->toArray();

            //在线状态的推广计划任务id
            $taskids = PromotionTaskDetailModel::getInstance()->getWhere(['appid'=>$appid,'status'=>'2','task_type'=>'0'])
                                                              ->orderBy('task_start_time','desc')->pluck('task_id')->toArray();

            if($isNowTime==false){
                //这样做确保，已同步的任务已被下架，需要更新状态

                //在线状态的任务id
                $onelineTaskIds = NovelSpreadModel::getInstance()->getWhere(['app_id'=>$appid,'task_status'=>2,'isdel'=>0])
                                                                 ->pluck('task_id')->toArray();

                $taskids = array_unique(array_merge($taskids,$onelineTaskIds));
                $limit = 100;
                //count($taskids)>300 && $limit = 70;
                //count($taskids)>500 && $limit = 100;

                $pageData = Cache::get('novel_detail_page_'.$appid);
                $page = !empty($pageData['totalCount']) && $pageData['totalCount']>($pageData['pageNo']*$limit) ? $pageData['pageNo']+1 : 1;
                list($taskids, $pageData) = $this->buildPage($taskids,$page,$limit);
                Cache::set('novel_detail_page_'.$appid,$pageData);

                //如果当天有新剧上线，每次同步都带上新剧同步，做到实时性
                $newTaskIds && $taskids && $taskids = array_unique(array_merge($newTaskIds,$taskids));
            }else{
                $taskids = $newTaskIds;
            }

            $statusMap = [];
            foreach($taskids as $taskid){
                $taskDetail = DouYinOpenApp::getInstance()->searchTaskInfo($appid,$taskid,$type=1);
                if(empty($taskDetail['data']['tasks'])) {
                    continue;
                }

                foreach($taskDetail['data']['tasks'] as $task) {
                    $task = array_change_key_case($task,CASE_LOWER);
                    $this->autoCreateTableAndInsertData(
                        [
                            'table'         => 'video_douyin_promotion_task_detail',
                            'keyid'         => 'promotion_task_detail_id',
                            'attributes'    => $task,
                            'update_fields' => ['appid', 'task_id'],
                        ]
                    );

                    if(in_array($taskid,$totalTaskIds)){
                        //如果已存在，就更新状态即可
                        $statusMap[$task['status']][] = $taskid;
                    }else{
                        //如果是小说的，尖叫故事和奇热故事，佣金比例大于1的过滤掉
                        if(in_array($appid,['ttd572a3cf4a4167a901','ttf426829b6b141c3f01']) && $task['payment_allocate_ratio']>100){
                            //continue;
                        }

                        //不存在就添加短剧
                        $this->insertSkitData($task,$appid,$businessMap);
                    }
                }

                usleep(100000);
            }

            //批量更新变化任务状态
            foreach ($statusMap as $status=>$statusTaskids){
                $update = ['task_status'=>$status];
                if($status!=2){
                    $update['status'] = 0;
                }
                NovelSpreadModel::getInstance()->getWhere([['task_id','in',$statusTaskids]])->update($update);
            }

            //检查当前小程序任务都不符合在前端显示，就在该商家状态下架，否则上架
            $where = ['task_status'=>'2','app_id'=>$appid,'status'=>1,'isdel'=>0];
            $count = NovelSpreadModel::getInstance()->getWhere($where)->count();
            if($count==false){
                NovelBusinessModel::getInstance()->getWhere(['id'=>$business['business_id']])->update(['status'=>0]);
            }else{
                NovelBusinessModel::getInstance()->getWhere(['id'=>$business['business_id']])->update(['status'=>1]);
            }
        }

        //最后把插入的任务数据通知到钉钉
//        $header = '【抖音】拉取到新任务数据: '."\n";
//        $content = '';
//        foreach ($this->insertTaskDatas as $val){
//            $contentType = '短剧';
//            if(in_array($val['appid'],['ttd572a3cf4a4167a901','ttf426829b6b141c3f01'])){
//                $contentType = '小说';
//            }
//            $content .= ' 【'.$contentType.'-'.($businessMap[$val['appid']]['app_name']??'').'】 '.$val['task_name']."\n";
//        }
//
//        if($content){
//            $token = config('param.dingding_notice')['data_token'];
//            Common::sendDingDingNotice($header.$content,$token);
//        }

        return 'success';
    }

    protected function insertSkitData($task,$appid,$businessMap)
    {
        $startPos = mb_strpos($task['task_name'],'《');
        $endPos = mb_strpos($task['task_name'],'》');
        if($startPos!==false && $endPos!==false){
            $task['task_name'] = mb_substr($task['task_name'],$startPos+1,$endPos-($startPos+1));
        }

        if($task['status']==2){
            //如果已经存在比当前任务更小的比例，则不添加当前任务
            $where = [
                'app_id'=>$task['appid'],
                'title'=>$task['task_name'],
                'task_status'=>2,
                'isdel'=>0,
                ['payment_allocate_ratio','<',$task['payment_allocate_ratio']],
            ];

            $first = NovelSpreadModel::getInstance()->getWhere($where)->count();
            if($first){
                //存在相同名字的任务，大于原来的，直接返回
                return false;
            }
        }

        $this->insertCommonData($businessMap[$appid],$task);

        $this->insertTaskDatas[] = ['task_name'=>$task['task_name'],'appid'=>$task['appid']];

        return true;
    }

    /**
     *  插入通用任务数据，只有任务数据情况下插入
     * @param $businessData
     * @param $task
     * @return int
     * @throws \app\exception\IndexException
     */
    public function insertCommonData($businessData,$task)
    {
        $mainImage = $task['task_icon'];
        $mainImageFileName = substr(md5(uniqid().time()),-26).'.jpg';
        try{
            $res = TencentCos::getInstance()->uploadLocalFile($mainImage,'douyin/'.($businessData['type']??'novel'),$mainImageFileName);
            if(isset($res['Location'])){
//                $image = $res['request-url'].'?x-oss-process=image/resize,h_306,m_lfit';
//                $res = Upload::getInstance()->stringUploadFile($image,($businessData['type']??'skit'));
                $mainImage = 'https://'.$res['Location'];
            }
        }catch (\Exception $e){}

        $insert = [
            'title'=>$task['task_name'],
            'main_image'=>$mainImage,
            'desc'=>'',
            'platform'=>$businessData['platform'],
            'business_id'=>$businessData['business_id'],
            'data_source_key'=>'common_task',
            'data_source_id'=>'0',
            'episode_num'=>'0',
            'is_end'=>0,
            'start_time'=>date('Y-m-d H:i:s',$task['task_start_time']),
            'labels'=>'',
            'status'=>0,

            'app_id'=>$task['appid'],
            'task_id'=>$task['task_id'],
            'task_start_time'=>date('Y-m-d H:i:s',$task['task_start_time']),
            'task_end_time'=>date('Y-m-d H:i:s',$task['task_end_time']),
            'task_settle_type'=>$task['task_settle_type'],
            'payment_allocate_ratio'=>$task['payment_allocate_ratio'],
            'task_refund_period'=>$task['task_refund_period'],
            'task_status'=>$task['status'],
        ];

        return NovelSpreadModel::getInstance()->saveData($insert);
    }


    /**
     * 查询团长和用户绑定关系
     * @param int $page
     * @param int $limit
     * @param null $userSn
     * @return string
     * @throws \Exception
     */
    public function sysncAgentAndUidBind($page=1,$limit=100,$userSn=null)
    {
        $data = DouYinOpenApp::getInstance()->searchBindRecord($page,$limit,null,null,$userSn);
        //var_dump($data);
        if(!empty($data['data']['results'])){
            foreach($data['data']['results'] as $val){
                $this->autoCreateTableAndInsertData(
                    [
                        'table'=>'video_douyin_promotion_plan_user_bind',
                        'keyid'=>'id',
                        'attributes'=>$val,
                        'update_fields'=>['agency_talent_uid','agent_id','douyin_id','bind_time']
                    ]
                );
            }
            if($data['data']['total_count']>($page*$limit)){
                $page++;
                $this->sysncAgentAndUidBind($page,$limit);
            }
        }

        return 'success';
    }

    /**
     * 获取每天用户收益数据
     * @param int $page
     * @param int $limit
     * @return string
     * @throws \Exception
     */
    public function sysncDailyIncomeData($page=1,$limit=10000)
    {
        $startTime = strtotime(date('Y-m-d',strtotime('-3 day')));
        $endTime = time()-(86400*2);
        $time = $startTime;

        $publicStartTime = strtotime(date('Y-m-d',strtotime('-89 day')));
        $publicEndTime = time();
        $appids = CooperateAppidModel::getInstance()->getWhere(['platform'=>1,'isdel'=>0])->pluck('name','appid')->toArray();
        while ($time<$endTime){
            foreach($appids as $appid=>$name){
                $billingData = date('Y-m-d',$time);
                $data = DouYinOpenApp::getInstance()->searchVideoDailyData($billingData,$publicStartTime,$publicEndTime,$page,$limit,$appid);
                if(!empty($data['data']['results'])){
                    foreach($data['data']['results'] as $val){
                        $val = array_change_key_case($val,CASE_LOWER);
                        $val['appid'] = $appid;
                        $val['app_name'] = $name;
                        $val['taskid'] = (string)$val['taskid'];
                        $val['videoid'] = (string)$val['videoid'];
                        $this->autoCreateTableAndInsertData(
                            [
                                'table'=>'video_douyin_daily_income_data',
                                'keyid'=>'id',
                                'attributes'=>$val,
                                'update_fields'=>['taskid','videoid','date']
                            ]
                        );

                        $val['id'] = Db::table('video_douyin_daily_income_data')->where(['videoid'=>$val['videoid'],'taskid'=>$val['taskid'],'date'=>$val['date']])->value('id');

                        //充值收益
                        if(!empty($val['billinggmv1d']) || !empty($val['billingrefundgmv1d'])){
                            $this->fillPayIncomeData2($val,1);
                        }
                        //广告收益
                        if(!empty($val['adsharecost1d'])){
                            $this->fillPayIncomeData2($val,2);
                        }
                    }
                }

                usleep(500000);
            }
            $time += 86400;
            sleep(3);
        }

        return 'success';
    }

    /**
     * 填充达人收益
     * @param $param
     * @param $incomeType
     * @return mixed
     * @throws \App\Exceptions\IndexException
     */
    public function fillPayIncomeData2($param,$incomeType)
    {
        $param = array_change_key_case($param,CASE_LOWER);
        if(!empty($param['user_sn'])){
            $userSn = $param['user_sn'];
        }else{
            //获取用户编号
            $where = ['douyin_id'=>$param['douyinid'],['bind_time','<',$param['publishtime']]];
            $userSn = Db::table('video_douyin_promotion_plan_user_bind')->where($where)->orderBy('bind_time','desc')->value('agency_talent_uid');
        }

        //获取小说信息
        $fields = ['title','main_image','business_id',DB::raw('novel_sn skit_sn'),'really_income','virtual_income','total_income'];
        $novelData = NovelSpreadModel::getInstance()->getWhere(['task_id'=>$param['taskid']])->first($fields);

        //获取任务详情信息
        $anchorTitle = Db::table('video_douyin_promotion_task_detail')->where(['task_id'=>$param['taskid']])->value('anchor_title');
        $paymentAllocateRatio = Db::table('video_douyin_promotion_task_detail')->where(['task_id'=>$param['taskid']])->value('payment_allocate_ratio');

        //达人奖励比例
        $user = UserModel::getInstance()->getWhere(['user_sn'=>$userSn])->first(['user_role','agent_level','reward_plan_id']);
        $levelRewardsFirst=false;
        if($user['reward_plan_id']>0){
            $levelRewardsFirst = RewardPlanModel::getInstance()->find($user['reward_plan_id']);
        }
        if($levelRewardsFirst==false){
            $levelRewardsFirst = RewardPlanModel::getInstance()->find(1);
        }
        //获取用户代理级别
        $agentLevel = UserModel::getInstance()->getUserAgentVip($userSn,$param['date']);
        $userTalentRate = json_decode($levelRewardsFirst['v'.$agentLevel.'_plan_data'],true)['talent_rate'];

        //奖励比例
        $promotionRate = round($paymentAllocateRatio/105,2);
        $promotionRates = explode('.',(string)$promotionRate);
        $promotionRates[1] = $promotionRates[1]??'0';
        $promotionRate = (float)($promotionRates[0].'.'.substr($promotionRates[1],0,1));
        $officialRate = (float)round($userTalentRate-$promotionRate,1);
        $officialRate = $officialRate>0 ? $officialRate : 0.0;

        $payAmount = 0;
        $getAmount = 0;
        $refundAmount = 0;
        if($incomeType==1){
            //充值金额
            $param['billinggmv1d'] && $payAmount = round($param['billinggmv1d']/100,2);
            $refundAmount = round($param['billingrefundgmv1d']/100,2);
            $getAmount = ($payAmount-$refundAmount);
        }elseif($incomeType==2){
            //广告金额
            $payAmount = round($param['adsharecost1d']/100,2);
            $getAmount =$payAmount;
        }

        //填充充值收益
        $incomeAmountFloat = round(abs($getAmount)*$userTalentRate/100,8);
        $incomeAmount = explode('.',(string)$incomeAmountFloat);
        $incomeAmount[1] = $incomeAmount[1]??'00';
        $incomeAmount = (float)($incomeAmount[0].'.'.substr($incomeAmount[1],0,2));

        $promotionRewardFloat = round(abs($getAmount)*$promotionRate/100,8);
        $promotionReward = explode('.',(string)$promotionRewardFloat);
        $promotionReward[1] = $promotionReward[1]??'00';
        $promotionReward = (float)($promotionReward[0].'.'.substr($promotionReward[1],0,2));
        $promotionReward = (float)($promotionRewardFloat<0.01 && $promotionRewardFloat>0 ? 0.01 : $promotionReward);

        $officialRewardFloat = (float)($incomeAmountFloat-$promotionRewardFloat);
        $officialReward = explode('.',(string)$officialRewardFloat);
        $officialReward[1] = $officialReward[1]??'00';
        $officialReward = (float)($officialReward[0].'.'.substr($officialReward[1],0,2));
        $officialReward = (float)($officialRewardFloat<0.01 && $officialRewardFloat>0 ? 0.01 : $officialReward);

        $using = $getAmount<0 ? '-':'';
        $skitIncomeData = [
            'user_sn'=>$userSn,
            'income_amount'=>$using.$incomeAmount,
            'pay_amount'=>$payAmount,
            'level_type'=>0,
            'income_source_user_sn'=>0,
            'pay_time'=>$param['date'],
            'source_table'=>'video_douyin_daily_income_data',
            'source_id'=>$param['id']??0,
            'platform'=>'1',
            //'business_logo'=>$business['logo']??'',
            'business_name'=>$param['app_name']??($param['microapptitle']??''),
            'status'=>0,

            'title'=>$param['taskname']??'',
            'main_image'=>$novelData['main_image']??'',
            'novel_sn'=>$novelData['skit_sn']??'',
            'author'=>$param['author']??'',
            'anchor_title'=>$anchorTitle??'',
            'refund_amount'=>$refundAmount,
            'videolink'=>$param['videolink']??'',
            'official_reward'=>$using.$officialReward,
            'promotion_reward'=>$using.$promotionReward,
            'taskid'=>$param['taskid'],
            'videoid'=>$param['videoid'],
            'reward_rate'=>$userTalentRate,
            'promotion_rate'=>$promotionRate,
            'official_rate'=>$officialRate,
            'douyin_id'=>$param['douyinid'],
            'app_id'=>$param['appid']??'',
            'agent_level'=>$agentLevel,
            'reward_plan_id'=>$levelRewardsFirst['reward_plan_id']??1,
            'income_type'=>$incomeType,
        ];
        if(strtotime($skitIncomeData['pay_time'])+(8*86400)<time()){
            $skitIncomeData['settle_time'] = date('Y-m-d H:i:s',strtotime($skitIncomeData['pay_time'])+(8*86400));
            $skitIncomeData['status'] = 1;
        }

        //如果补贴小于0 ，则是退款，直接结算扣掉流水金额
        if($skitIncomeData['official_reward']<0){
            $skitIncomeData['status'] = 2;
            $skitIncomeData['settle_time'] = $param['date'];
        }

        $userIncomeFlow = [
            'user_sn'=>$userSn,
            'amount'=>$skitIncomeData['official_reward'],
            'type'=>1,
            'status'=>$skitIncomeData['status'],
            'income_date'=>$skitIncomeData['pay_time'],
        ];
        !empty($skitIncomeData['settle_time']) && $userIncomeFlow['settle_time'] = $skitIncomeData['settle_time'];

        if($skitIncomeData['official_reward']<0){
            $userIncomeFlow['status'] = 2;
            $userIncomeFlow['settle_time'] = $param['date'];
        }
        try{
            Db::connection('mysql')->beginTransaction();

            //不存在就添加，存在就跳过
            $uniValues = [
                'user_sn'=>$userSn,
                'source_table'=>$skitIncomeData['source_table'],
                'source_id'=>$skitIncomeData['source_id'],
                'income_type'=>$incomeType,
            ];
            $count = UserPromotionOrderIncomeModel::getInstance()->getWhere($uniValues)->count();
            if($count==false){
                UserPromotionOrderIncomeModel::getInstance()->insert($skitIncomeData);
            }

            $orderIncomeId = UserPromotionOrderIncomeModel::getInstance()->getWhere($uniValues)->value('id');
            $uniValues = [
                'source_table'=>UserPromotionOrderIncomeModel::getInstance()->getTable(),
                'sourceid'=>$orderIncomeId,
            ];
            $count = UserIncomeFlowModel::getInstance()->getWhere($uniValues)->count();
            if($count==false){
                $userIncomeFlow['source_table'] = UserPromotionOrderIncomeModel::getInstance()->getTable();
                $userIncomeFlow['sourceid'] = $orderIncomeId;
                UserIncomeFlowModel::getInstance()->insert($userIncomeFlow);
            }

            Db::connection('mysql')->commit();
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        //todo 邀请奖励
        $this->fillAgentIncomeData($userSn,$orderIncomeId);

        return $orderIncomeId;
    }
}